# Created by 黄景涛
# DATE: 2025/4/29

import re
import logging
from re import Match
from typing import Any, Dict, Union
from var_hot_loading.tools.yaml_util import DictKey, read_yaml
from var_hot_loading.tools import hot_tool

logger = logging.getLogger()


def render(sr: Union[str, dict]) -> Union[str, dict]:
    """ 变量占位渲染 """
    pf = ParserFactory()

    sr_type = sr.__class__
    v, unfilled_sr = pf.create_parser(str(sr))

    # 递归终止条件
    if v is None:
        return sr

    # 当前层处理
    str_v = str(v)
    filled_sr = unfilled_sr.replace('{placeholder}', str_v)

    v_type = v.__class__
    v_not_string = v_type is not str and len(str_v) == len(filled_sr)
    if sr_type is not str or v_not_string:
        filled_sr = eval(filled_sr)

    # 递进到下一层
    return render(filled_sr)


class NameSpace:
    # 处理类对应的context上下文
    single_context = read_yaml('config/config.yaml')
    func_context = hot_tool.__dict__
    custom_context = {"request": {"data": {"name": "主机1"}},
                      "response": {"data": {"info": [{"name": "响应名称1"}, {"name": "响应名称2"}]}}}


class ParserFactory(NameSpace):
    # 占位替代文案
    placeholder_symbol = '{placeholder}'

    def create_parser(self, text) -> tuple[Union[object, None], Union[str, None]]:
        """ 匹配器工厂 """
        custom_pattern = r'\$\{((request|response)[^{}()]+)}'
        single_pattern = r'\$\{([^{}()]+)}'
        function_pattern = r'\$\{(\w+)\((.*)\)}'

        custom_ans = self.create_custom_parser(custom_pattern, text)
        if custom_ans != -1:
            return custom_ans

        single_ans = self.create_single_parser(single_pattern, text)
        if single_ans != -1:
            return single_ans

        func_ans = self.create_func_parser(function_pattern, text)
        if func_ans != -1:
            return func_ans

        return None, None

    def create_custom_parser(self, pattern, text):
        custom_match = re.search(pattern, text)
        if custom_match is None:
            return -1

        context = self.custom_context
        val = CustomRuleParser(custom_match).hot_parse(context)
        if not isinstance(val, str):
            pattern = "('?)" + pattern + "('?)"
        unfilled_text = re.sub(pattern, self.placeholder_symbol, text)
        return val, unfilled_text

    def create_single_parser(self, pattern, text):
        single_match = re.search(pattern, text)
        if single_match is None:
            return -1

        context = self.single_context
        val = SingleVarParser(single_match).hot_parse(context)
        if not isinstance(val, str):
            pattern = "('?)" + pattern + "('?)"
        unfilled_text = re.sub(pattern, self.placeholder_symbol, text)
        return val, unfilled_text

    def create_func_parser(self, pattern, text):
        func_match = re.search(pattern, text)
        if func_match is None:
            return -1

        context = self.func_context
        val = FuncVarParser(func_match).hot_parse(context)
        if not isinstance(val, str):
            pattern = "('?)" + pattern + "('?)"
        unfilled_text = re.sub(pattern, self.placeholder_symbol, text)
        return val, unfilled_text


class BaseParser:
    """ 变量占位符规则 """

    def __init__(self, match: Match):
        """ 变量占位匹配 """
        self.match = match

    def hot_parse(self, context: Dict[str, Any]) -> Any:
        raise NotImplementedError


class SingleVarParser(BaseParser):
    """ 常规变量解析 """

    def hot_parse(self, context: Dict[str, Any]) -> Any:
        """
        匹配 ${var_name} 形式
        :param context: 上下文为字典
        :return:
        """
        if self.match is None:
            return None

        var_name = self.match.group(1)
        dk = DictKey(var_name)
        val = dk.get(context)
        if val:
            return val
        return None


class CustomRuleParser(SingleVarParser):
    """ 自定义规则器解析 """

    def hot_parse(self, context: Dict[str, Any]) -> Any:
        return super().hot_parse(context)


class FuncVarParser(BaseParser):
    """ 函数变量解析 """

    def hot_parse(self, context: Dict[str, Any]) -> Any:
        """
        匹配 ${f(*args, **kwargs)} 形式
        :param context: 上下文为工具函数模块
        :return:
        """
        if self.match is None:
            return None

        func_name = self.match.group(1)
        args_str = self.match.group(2)
        func = context.get(func_name)
        # 参数检查并渲染填充
        filled_args = self._fill_args(args_str, render)
        return self._call(func, filled_args)

    @staticmethod
    def _fill_args(s, handler):
        """
        填充变量得到最终的参数
        :param s: 包含嵌套占位符的原始字符串
        :param handler (function): 处理器，这里为render函数
        :return:  所有占位符被替换后的最终字符串
        """
        pattern = r'(\$\{[^{}]*})'  # 匹配最内层的占位符
        while True:
            matches = list(re.finditer(pattern, s))
            if not matches:
                break
            # 从后向前替换，避免影响后续匹配的位置
            for match in reversed(matches):
                start = match.start()
                end = match.end()
                content = match.group(1)
                replacement = handler(content)
                s = s[:start] + str(replacement) + s[end:]
        return s

    @staticmethod
    def _call(func, args_str: str):
        """
        调用函数
        :param func:  函数对象
        :param args_str: 参数集的字符串表示
        :return: 调用结果
        """
        if not callable(func):
            return None

        try:
            # 解析参数
            args = []
            kwargs = {}
            for arg in args_str.split(','):
                arg = arg.strip().strip("'\"")
                if arg == '':
                    continue

                if '=' in arg:
                    key, value = arg.split('=')
                    kwargs[key.strip()] = value
                else:
                    args.append(arg)

            return func(*args, **kwargs)
        except Exception as e:
            logger.error(f"无法调用函数 {func}: {e}")
            return None
